package com.kede.app.service.impl;

import com.kede.app.domain.SysArea;
import com.kede.app.repository.SysAreaRepository;
import com.kede.app.service.SysAreaService;
import com.kede.app.service.dto.SysAreaDto;
import com.kede.app.service.dto.SysAreaQueryCriteria;
import com.kede.app.service.impl.vo.AreaInfoVo;
import com.kede.app.service.impl.vo.JsDict;
import com.kede.app.service.mapstruct.SysAreaMapper;
import com.kede.dictenum.AreaDictEnum;
import com.kede.utils.FileUtil;
import com.kede.utils.PageUtil;
import com.kede.utils.QueryHelp;
import com.kede.utils.ValidationUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;

/**
* @description 服务实现
* @author Pr.li
* @date 2023-04-19
**/
@Service
@RequiredArgsConstructor
public class SysAreaServiceImpl implements SysAreaService {

    private final SysAreaRepository sysAreaRepository;
    private final SysAreaMapper sysAreaMapper;

    @Override
    public Map<String,Object> queryAll(SysAreaQueryCriteria criteria, Pageable pageable){
        Page<SysArea> page = sysAreaRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder),pageable);
        return PageUtil.toPage(page.map(sysAreaMapper::toDto));
    }

    @Override
    public List<SysAreaDto> queryAll(SysAreaQueryCriteria criteria){
        return sysAreaMapper.toDto(sysAreaRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder)));
    }

    @Override
    @Transactional
    public SysAreaDto findById(Integer id) {
        SysArea sysArea = sysAreaRepository.findById(id).orElseGet(SysArea::new);
        ValidationUtil.isNull(sysArea.getId(),"SysArea","id",id);
        return sysAreaMapper.toDto(sysArea);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public SysAreaDto create(SysArea resources) {
        return sysAreaMapper.toDto(sysAreaRepository.save(resources));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(SysArea resources) {
        SysArea sysArea = sysAreaRepository.findById(resources.getId()).orElseGet(SysArea::new);
        ValidationUtil.isNull( sysArea.getId(),"SysArea","id",resources.getId());
        sysArea.copy(resources);
        sysAreaRepository.save(sysArea);
    }

    @Override
    public void deleteAll(Integer[] ids) {
        for (Integer id : ids) {
            sysAreaRepository.deleteById(id);
        }
    }

    @Override
    public void download(List<SysAreaDto> all, HttpServletResponse response) throws IOException {
        List<Map<String, Object>> list = new ArrayList<>();
        for (SysAreaDto sysArea : all) {
            Map<String,Object> map = new LinkedHashMap<>();
            map.put("名称", sysArea.getName());
            map.put("地区编码，一般为区一级", sysArea.getAdcode());
            map.put("城市编码", sysArea.getCitycode());
            map.put(" pid",  sysArea.getPid());
            map.put("排序", sysArea.getSort());
            map.put("1 省， 2 市  ，3区", sysArea.getLevel());
            list.add(map);
        }
        FileUtil.downloadExcel(list, response);
    }

    @Override
    public AreaInfoVo findDetailByAdcode(Integer adcode) {
        Optional<SysArea> sysAreaOption = sysAreaRepository.getSysAreaByAdcode(adcode);
        if (!sysAreaOption.isPresent()){
            throw new NullPointerException("无效的地区编码:"+adcode);
        }
        SysArea sysArea = sysAreaOption.get();
        AreaDictEnum areaDictEnum = AreaDictEnum.valueOfCode(sysArea.getLevel());
        AreaInfoVo areaInfoVo = new AreaInfoVo();
        SysArea province;
        switch (areaDictEnum) {
            case province:
                //省
                areaInfoVo.setProvinceCode(sysArea.getAdcode());
                areaInfoVo.setProvinceName(sysArea.getName());
                break;
            case ciry:
                //市
                province = sysAreaRepository.getById(sysArea.getPid());
                areaInfoVo.setProvinceCode(province.getAdcode());
                areaInfoVo.setProvinceName(province.getName());
                areaInfoVo.setCityCode(sysArea.getAdcode());
                areaInfoVo.setCityName(sysArea.getName());

                break;
            case area:
                //区
                SysArea city = sysAreaRepository.getById(sysArea.getPid());
                province = sysAreaRepository.getById(city.getPid());
                areaInfoVo.setProvinceCode(province.getAdcode());
                areaInfoVo.setProvinceName(province.getName());
                areaInfoVo.setCityCode(city.getAdcode());
                areaInfoVo.setCityName(city.getName());
                areaInfoVo.setAreaCode(sysArea.getAdcode());
                areaInfoVo.setAreaName(sysArea.getName());
                break;
        }
//        DictService
        return areaInfoVo.toAddress();
    }

    /**
     * 将数据库地址 格式化成前端js需要的地址格式
     */
    @Override
    public List<JsDict> formatAreatoJS(Integer adcode){
        List<SysArea> province;
        if (adcode==null){
            province = sysAreaRepository.findAllByLevelOrderBySort(1);
        }else{
            province =sysAreaRepository.findAllByAdcodeOrderBySort(adcode);
        }
        List<SysArea> city = sysAreaRepository.findAllByLevelOrderBySort(2);
        List<SysArea> area = sysAreaRepository.findAllByLevelOrderBySort(3);

        List<JsDict> list = new ArrayList<>();
        province.forEach(p -> {
            JsDict pjsDict = new JsDict();
            pjsDict.setValue(p.getAdcode());
            pjsDict.setLabel(p.getName());
            ArrayList<JsDict> creaList = new ArrayList<>();
            for (SysArea c : city) {
                if (c.getPid().equals(p.getId())) {
                    JsDict cjsDict = new JsDict();
                    cjsDict.setLabel(c.getName());
                    cjsDict.setValue(c.getAdcode());
                    ArrayList<JsDict> areaList = new ArrayList<>();
                    for (SysArea a : area) {
                        if (a.getPid().equals(c.getId())) {
                            JsDict ajsDict = new JsDict();
                            ajsDict.setLabel(a.getName());
                            ajsDict.setValue(a.getAdcode());
                            areaList.add(ajsDict);
                        }
                    }
                    cjsDict.setChildren(areaList);
                    creaList.add(cjsDict);
                }
            }
            pjsDict.setChildren(creaList);
            list.add(pjsDict);
        });
        return list;
    }


}